<?php
/*-- Project Introduce --*/
namespace JCAT\Core\OOP ;

use JCAT\Core ;
use JCAT\Core\Locale ;

/**
 * 递归地检查给定的两个类(接口)之间的 继承 关系。
 * 如果 参数 $SubClass 和 $sBaseClass 相同，仍然返回 true ，表示 “IsKindOf” 关系成立。
 * 如果 $SubClass 或 $sBaseClass 传入不存在的类名，简单的返回 false ，而不会抛出异常，或进行更严重的错误处理。
 * php 的原生函数 is_subclass_of() 只对 直接继承提供判断，本函数是对  is_subclass_of() 的加强。
 * 注：is_subclass_of() 在判断直接继承时，仍然有用。
 *
 * @access	public
 * @param	$SubClassOrInstance	string,object	子类，或 子类的一个实例
 * @param	$sBaseClass			string			父类
 * @return	bool
 */
function IsKindOf(  $SubClassOrInstance,  $sBaseClass ) 
{
	// 接口
	if( PHPClassLoader::GetGlobalInstance()->ClassExists($sBaseClass,true) )
	{
		return HasImplementedTo($SubClassOrInstance,$sBaseClass) ;
	}

	// 类
	else
	{
		// 统一类名
		if( is_object($SubClassOrInstance) )
		{
			$sSubClassOrInstanceName = get_class($SubClassOrInstance) ;
		}
		elseif( is_string($SubClassOrInstance) )
		{
			$sSubClassOrInstanceName = $SubClassOrInstance ;
		}
		else
		{
			return false ;
		}
		
		// 子类名 即为  父类名
		if( $sSubClassOrInstanceName==$sBaseClass )
		{
			return true ;
		}
		
		// 递归检查
		$sParentClass = get_parent_class($sSubClassOrInstanceName) ;
		if(!$sParentClass)
		{
			return false ;
		}

		return IsKindOf($sParentClass,$sBaseClass) ;
	}
}


/**
 * 检查一个 类或对象 是否实现了某个接口
 *
 * 
 * @access	public
 * @param	$ClassOrObject		string,object	待检查的类或对象
 * @param	$sInterface			string			应实现的接口名
 * @param	$bStrictly=false	bool			是否严格检查 所有 的 接口的所有方法均已实现（非抽象方法）
 * @return	bool
 */
function HasImplementedTo(  $ClassOrObject,  $sInterface,  $bStrictly=false ) 
{
	if( is_object($ClassOrObject) )
	{
		$sClassName = get_class($ClassOrObject) ;
	}
	elseif( is_string($ClassOrObject) )
	{
		$sClassName = $ClassOrObject ;
	}
	else
	{
		return false ;
	}
	
	// 类型检查
	if( !is_string($sClassName) )
	{
		return false ;
		//throw new Core\Exception("参数 \$ClassOrObject({$sClassName}) 必须是一个 类名(sting) 或 对象",__FUNCTION__,__LINE__,'$Revision: 2147 $') ;
	}
	
	// 检查 类 和 接口 是否都有效
	if( !class_exists($sClassName) or !interface_exists($sInterface) )
	{
		return false ;
		//throw new Core\Exception("参数 \$ClassOrObject({$sClassName}) 和 \$sInterface({$sInterface}) 必须是已定义的对象和接口。",__FUNCTION__,__LINE__,'$Revision: 2147 $') ;
	}

	$aReflectionClass = new ReflectionClass( $sClassName ) ;
	$arrInterfaceRefs = $aReflectionClass->getInterfaces() ;
	foreach($arrInterfaceRefs as $aInterfaceRef)
	{
		if( $aInterfaceRef->getName()!=$sInterface )
		{
			continue ;
		}


		// 找到 匹配的 接口 ========================
		if(!$bStrictly)
		{
			return true ;
		}

		// 依次检查 接口中的每个方式， 是否实现
		$arrInterfaceFuncs = get_class_methods($sInterface) ;
		foreach ($arrInterfaceFuncs as $sFuncName)
		{
			$aReflectionMethod = $aReflectionClass->getMethod($sFuncName) ;
			// 发现 尚为抽象 的方法
			if( $aReflectionMethod->isAbstract() )	
			{
				return false ;
			}
		}
		return true ;
		// ======================================
	}


	// 递归检查父类
	if( $sParentName=get_parent_class($sClassName) )
	{
		return HasImplementedTo( $sParentName,$sInterface,$bStrictly ) ;
	}
	else
	{
		return false ;
	}
}

/**
 * 动态地创建对象
 * 
 * @param	$sClassName		string	类名
 * @param	$arrParams		array	参数
 * @return	string
 */
function CreateObject ( $sClassName, array $arrParams=array() )
{
	if( !class_exists($sClassName) )
	{
		throw new Core\Exception( Locale\se('参数 $sClassName 必须是有效的类名。','JCAT',null), __FUNCTION__,__LINE__,'$Revision: 2147 $' ) ;
	}
	
	$arrArgList = array() ;
	foreach($arrParams as $sKey=>$Item)
	{
		$arrArgList[] = "\$arrParams[$sKey]" ;
	}
	$sArgList = implode(', ',$arrArgList) ;
	
	return eval("return new $sClassName( {$sArgList} );") ;
}

/**
 * 在 __sleep() 魔术函数中，如果直接返回一个 private 属性的名称，则对 子类对象 serialize 操作时 无效。
 * 此函数 返回一个 任何时候 都有效的  属性名称。
 * 
 * @param	$sPropertyName		string	属性名称
 * @param	$sClassName			string	正在载入的 类名 或 接口名
 * @return	void
 */
function MakePrivateNameForSerialize( $sPropertyName, $sClassName )
{
	return "\0{$sClassName}\0{$sPropertyName}" ;
}

/**
 * Description
 *
 * @param	$sPropertyName
 * @return	string
 */
function MakePropertyNameForSerialize($sPropertyName)
{
	return "\0*\0{$sPropertyName}" ;
}

?>